module nehe.Window;

import derelict.opengl.gl;
import derelict.opengl.glu;
import derelict.sdl.sdl;

import tango.stdc.stringz;

import nehe.NeHeException;

/**
 * Module constructor. Here we load the GL, GLU and SDL shared libraries.
 */
static this()
{
	DerelictGL.load();
	DerelictGLU.load();
	DerelictSDL.load();
}

static ~this()
{
	if(SDL_WasInit(SDL_INIT_VIDEO) != 0)
	{
		SDL_Quit();
	}
}

public class Window
{
	private SDL_Surface* screen;

	public void create(int width = 800, int height = 600, int bitsPerPixel = 32, char[] title = "NeHe Window",
		bool fullscreen = false)
	{
		if(SDL_Init(SDL_INIT_VIDEO) != 0) 
		{
			throw new NeHeException("Failed to init SDL: " ~ getSDLError());
		}
		
		ushort[] bpp = bppToArray(bitsPerPixel);
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, bpp[0]);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, bpp[1]);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, bpp[2]);
		SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		
		// Set the title.
		SDL_WM_SetCaption(toStringz(title), null);

		// Flags tell SDL about the type of window we are creating.
		int flags = SDL_OPENGL;
		if(fullscreen)
		{
			flags |= SDL_FULLSCREEN;
		}

		// Create the window
		screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
		if(screen is null)
		{
			throw new NeHeException("Failed to create SDL surface: " ~ getSDLError());
		}
		
		//SDL doesn't trigger off a ResizeEvent at startup, but as we need this for OpenGL, we do this ourself
		SDL_Event resizeEvent;
		resizeEvent.type = SDL_VIDEORESIZE;
		resizeEvent.resize.w = width;
		resizeEvent.resize.h = height;
		
		SDL_PushEvent(&resizeEvent);
	}

	public int getWidth()
	{
		return screen.w;
	}

	public int getHeight()
	{
		return screen.h;
	}

	/**
	 * Converts the given bits value to its array components.
	 * 
	 * Params:
	 *     bitsPerPixel = the bits per pixel value 
	 * Returns: The given value's components in an array.
	 */
	private ushort[] bppToArray(ushort bitsPerPixel)
	{
		switch(bitsPerPixel)
		{
			case 8:
				return new ushort[2, 3, 3];
			case 15:
				return new ushort[5, 5, 5];
			case 16:
				return new ushort[5, 6, 5];
			case 24:
			case 32:
				return new ushort[8, 8, 8];
			default:
				throw new NeHeException("Invalid bits per pixel.");
		}
	}

	/**
	 * Get the SDL error as a D string.
	 *
	 * Returns: A D string containing the current SDL error.
	 */
	private char[] getSDLError()
	{
		return fromStringz(SDL_GetError());
	}
}
